#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>

#define BUFSIZE   100
#define MAX(a,b)  ((a>b)?a:b)
#define   L    1
#define   B    2
#define   Q    3

struct msg{
    char name[8]; 
    char type;
    char package[BUFSIZE];
};
typedef struct msg MSG;

struct sockaddr_in server;
struct hostent *host;
void communicate();
static void bail();

int main(int argc,char **argv){

    int port;
    int conn_fd;
    socklen_t sin_size;
    sin_size = sizeof(struct sockaddr_in);
    MSG msg;

    if(argc != 3)
 	fprintf(stderr,"Usage:%s IP PORT",argv[0]);
    if((port = atoi(argv[2])) < 0)
	bail("port error");
    if((host = gethostbyname(argv[1])) == NULL)
	bail("host error");
    conn_fd = socket(AF_INET,SOCK_STREAM,0);
    memset(&server,0,sin_size);
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr = *((struct in_addr *)host->h_addr);
    
    if(connect(conn_fd,(struct sockaddr*)&server,sin_size) < 0)
	bail("connect error");
    printf("*******press user name:   ");
    fgets(msg.name,8,stdin);
    msg.type = 'L';

    if(write(conn_fd,&msg,sizeof msg) < 0)
        bail("write login");

    for(;;){
	communicate(stdin,conn_fd);
	close(conn_fd);
	exit(0);		
	}
    return 0;
}


static void bail(const char *on_what){

    fputs(strerror(errno),stderr);
    fputs(":",stderr);
    fputs(on_what,stderr);
    fputc('\n',stderr);
    exit(1);
}

void communicate(FILE *fp,int sockfd){

    int n;
    int maxfd;
    char rbuf[BUFSIZE];
    char wbuf[BUFSIZE];
    MSG msg;
    fd_set rset;
    FD_ZERO(&rset);
    while(1){
	FD_SET(fileno(fp),&rset);
        FD_SET(sockfd,&rset);
        maxfd = MAX(fileno(fp),sockfd);
   	select(maxfd + 1,&rset,NULL,NULL,NULL);
        if(FD_ISSET(fileno(fp),&rset)){
	    fgets(msg.package,BUFSIZE,stdin);
            if(memcmp(msg.package,"quit",4) == 0){
		msg.type = 'Q';
		if(write(sockfd,&msg,sizeof msg) < 0)
		    bail("write quit");
	    }
	    else{
		    msg.type = 'B';
		    if(write(sockfd,&msg,sizeof msg) < 0)
			bail("write brodecast");
  	    
	        }
	}

	if(FD_ISSET(sockfd,&rset)){
	    if((n = read(sockfd,&msg,sizeof msg)) == 0){
		printf("\nserver has close the pipe....\n");
                printf("press ENTER to exit....\n");
                getchar();
                exit(0);
		}
	    if(n < 0)
		bail("read error");

            switch(msg.type){
		    case 'L':
			printf("%s login\n",msg.name);
			break;
		    case 'B':
			printf("from %s> %s\n",msg.name,msg.package);
			break;
		    case 'Q':
			printf("%s quit\n",msg.name);
			break;
	    }
    	}
    }
}





